﻿using System;
using System.Diagnostics.Contracts;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sundstrom.Mvvm.Command
{
    /// <summary>
    ///     Relay command for asynchronous actions.
    /// </summary>
    public sealed class AsyncRelayCommand : ICommand
    {
        private readonly Func<Task> _execute;
        private readonly Func<bool> _canExecute;

        public AsyncRelayCommand(Func<Task> execute, Func<bool> canExecute)
        {
            Contract.Requires<ArgumentNullException>(execute != null);
            Contract.Requires<ArgumentNullException>(canExecute != null);

            _execute = execute;
            _canExecute = canExecute;
        }

        public AsyncRelayCommand(Func<Task> execute) 
        {
            Contract.Requires<ArgumentNullException>(execute != null);

            _execute = execute;
            _canExecute = null;
        }

        bool ICommand.CanExecute(object parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }

            return _canExecute();
        }

        public Task ExecuteAsync()
        {
            return _execute();
        }

        public bool CanExecute()
        {
            return _canExecute();
        }

        void ICommand.Execute(object parameter)
        {
           _execute();
        }

        public event EventHandler CanExecuteChanged;

        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}
